/*
 * @Author: hanyuanjiao
 * @Date: 2025-07-21 06:52:28
 * @LastEditors: Please set LastEditors
 * @LastEditTime: 2025-08-19 14:25:28
 * @Description: 请填写简介
 */
#ifndef SIMU8051_H
#define SIMU8051_H
#include <stdint.h>
#include "instr.h"

/**8051需要描述的存储器有
 * 1.程序存储器 64k
 * 2.内部数据存储器 128B，特殊功能寄存器128B
 * 3.外部存储器 64k
 * **/
// 程序存储器
#define MEM_CODE_SIZE (64 * 1024)
// 内部数据存储器
#define MEM_IRAM_SIZE 128
// 特殊功能寄存器
#define MEM_SFR_SIZE 128
// 外部存储器
#define MEM_XRAM_SIZE (64 * 1024)

// 8051存储结构
typedef struct _memory_t
{
    // 指代64k程序存储器，0x0000~0xFFFF
    uint8_t *code;
    // 内部数据存储器
    uint8_t iram[MEM_IRAM_SIZE];
    // 特殊功能寄存器
    uint8_t sfr[MEM_SFR_SIZE];
    // 外部存储器
    uint8_t xram[MEM_XRAM_SIZE];
} memory_t;

typedef struct _simu8051_t
{
    memory_t mem;
    // register pc
    uint16_t pc;
    uint32_t cycles;
    uint8_t  in_int;    //中断锁
} simu8051_t;

/**
 * @description: 重置PC,cycles,SP
 * @return {*}
 */
void simu8051_reset(void);
/**
 * @description: 8051初始化,包括程序存储器,(内部数据存储器,特殊功能寄存器),外部存储器
 * @return {*}
 */
void simu8051_init(void);
/**
 * @description: 将二进制程序加载到模拟器code
 * @param {uint8_t} *code
 * @return {*}
 */
void simu8051_load(uint8_t *code);
/**
 * @description: 返回PC值
 * @return {*}
 */
uint16_t simu8051_pc(void);
/**
 * @description: 返回sp值
 * @return {*}
 */
uint8_t simu8051_sp(void);
/**
 * @description: 取指
 * @param {instr_t} *instr
 * @return {*}
 */
void simu8051_fetch_instr(instr_t *instr);
/**
 * @description: 执行指令
 * @param {instr_t} *instr
 * @return {*}
 */
void simu8051_exec(instr_t *instr);
/**
 * @description:返回已执行的指令周期
 * @return {*}
 */
uint32_t simu8051_cycle(void);
/**
 * @description: 运行程序
 * @param {uint16_t} stop_addr 程序停止地址 0表示不需要
 * @param {uint32_t} stop_cycle 程序停止时运行的机器周期数 0表示不需要
 * @return {*}
 */
void simu8051_run(uint16_t stop_addr, uint32_t stop_cycle);

/**
 * @description: 实现方法放在main.c函数中
 * @param {char} c
 * @return {*}
 */
void simu8051_uart_write(char c);
/**
 * @description: 实现方法放在main.c函数中
 * @return {*}
 */
char simu8051_uart_read();
/**
 * @description: 实现方法放在main.c函数中,判断键盘是否有被按下,用于打开串口接收中断
 * @return {*}
 */
int simu8051_uart_rx_rdy();

#endif    // !SIMU8051_H
